home *** CD-ROM | disk | FTP | other *** search
/ Aminet 19 / Aminet 19 (1997)(GTI - Schatztruhe)[!][Jun 1997].iso / Aminet / text / tex / rtf2latex.lha / rtf2LaTeX / reader.c < prev    next >
C/C++ Source or Header  |  1997-02-28  |  38KB  |  1,539 lines

  1. /*
  2.     Need to document error code meanings.
  3.     Change document to reflect RTFFuncPtr.
  4.  
  5.     reader.c - RTF file reader.  Distribution 1.06a3.
  6.  
  7.     ASCII 10 (\n) and 13 (\r) are ignored and silently discarded
  8.     (although the read hook will still get a look at them.)
  9.  
  10.     "\:" is not a ":", it's a control symbol.  But some versions of
  11.     Word seem to write "\:" for ":".  This reader treats "\:" as a
  12.     plain text ":"
  13.  
  14.     This reader needs to catch \cf and \cb in the color table
  15.     reader?  (Doesn't yet.)
  16.  
  17.     19 Mar 93 Add hack to skip "{\*\keycode ... }" group in stylesheet
  18. */
  19.  
  20. # include    <stdio.h>
  21. # include    <ctype.h>
  22. # include    <string.h>
  23. # ifdef THINK_C
  24. #    include    "macintosh.h"
  25. # endif /* THINK_C */
  26. # ifdef __STDC__
  27. #    include    <stdlib.h>
  28. /* if it is a standard compiler, you should have stdarg. */
  29. #   ifndef VARARGS
  30. #       define STDARG
  31. #   endif /* !VARARGS */
  32. # else /* !__STDC__ */
  33. #    ifdef NO_MALLOC_H
  34.         extern char *malloc ();
  35. #    else /* NO_MALLOC_H */
  36. #       include    <malloc.h>
  37. #    endif /* NO_MALLOC_H */
  38. # endif /* !__STDC__ */
  39. # ifdef STDARG
  40. #    include    <stdarg.h>
  41. # else    /* !STDARG */
  42. #    ifdef VARARGS
  43. #       include    <varargs.h>
  44. #    endif /* VARARGS */
  45. # endif    /* !STDARG */
  46.  
  47. # include    "rtf.h"
  48.  
  49.  
  50. /*
  51.     Return pointer to new element of type t, or NULL
  52. */
  53.  
  54. # define    New(t)    ((t *) RTFAlloc ((int) sizeof (t)))
  55.  
  56.  
  57. # ifdef    SYSV
  58. # define    index    strchr
  59. # endif
  60.  
  61. /* The templates are needed, at least for the mac */
  62. # ifdef __STDC__
  63. static void     _RTFGetToken (void);
  64. static int      GetChar (void);
  65. static int      HexVal (char);
  66. static void     ReadFontTbl (void);
  67. static void     ReadColorTbl (void);
  68. static void     ReadStyleSheet (void);
  69. static void     ReadInfoGroup (void);
  70. static void     ReadPictGroup (void);
  71. static void     LookupInit (void);
  72. static void     Lookup (char*);
  73. static int      Hash (char*);
  74. static void     Error (char *format, ...);
  75. # else /* !__STDC__ */
  76. static void    _RTFGetToken ();
  77. static int    GetChar ();
  78. static int    HexVal ();
  79. static void    ReadFontTbl ();
  80. static void    ReadColorTbl ();
  81. static void    ReadStyleSheet ();
  82. static void    ReadInfoGroup ();
  83. static void    ReadPictGroup ();
  84. static void    LookupInit ();
  85. static void    Lookup ();
  86. static int    Hash ();
  87. static void    Error ();
  88. # endif /* !__STDC__ */
  89.  
  90.  
  91. /*
  92.     Public variables (listed in rtf.h)
  93. */
  94.  
  95. int    rtfClass;
  96. int    rtfMajor;
  97. int    rtfMinor;
  98. int    rtfParam;
  99. char    rtfTextBuf[rtfBufSiz];
  100. int    rtfTextLen;
  101.  
  102.  
  103. /*
  104.     Private stuff
  105. */
  106.  
  107. static int    pushedChar;    /* pushback char if read too far */
  108.  
  109. static int    pushedClass;    /* pushed token info for RTFUngetToken() */
  110. static int    pushedMajor;
  111. static int    pushedMinor;
  112. static int    pushedParam;
  113. static char    pushedTextBuf[rtfBufSiz];
  114.  
  115.  
  116. static RTFFont    *fontList = (RTFFont *) NULL;    /* these lists MUST be */
  117. static RTFColor    *colorList = (RTFColor *) NULL;    /* initialized to NULL */
  118. static RTFStyle    *styleList = (RTFStyle *) NULL;
  119.  
  120.  
  121. static FILE    *rtffp;
  122.  
  123.  
  124. /*
  125.     Initialize the reader.  This may be called multiple times,
  126.     to read multiple files.  The only thing not reset is the input
  127.     stream; that must be done with RTFSetStream().
  128. */
  129.  
  130. void RTFInit ()
  131. {
  132. int    i;
  133. RTFColor    *cp;
  134. RTFFont        *fp;
  135. RTFStyle    *sp;
  136. RTFStyleElt    *eltList, *ep;
  137. rtffp=stdin;
  138.  
  139.     /* initialize lookup table */
  140.     LookupInit ();
  141.  
  142.     for (i = 0; i < rtfMaxClass; i++)
  143.         RTFSetClassCallback (i, (RTFFuncPtr) NULL);
  144.     for (i = 0; i < rtfMaxDestination; i++)
  145.         RTFSetDestinationCallback (i, (RTFFuncPtr) NULL);
  146.  
  147.     /* install built-in destination readers */
  148.     RTFSetDestinationCallback (rtfFontTbl, ReadFontTbl);
  149.     RTFSetDestinationCallback (rtfColorTbl, ReadColorTbl);
  150.     RTFSetDestinationCallback (rtfStyleSheet, ReadStyleSheet);
  151.     RTFSetDestinationCallback (rtfInfo, ReadInfoGroup);
  152.     RTFSetDestinationCallback (rtfPict, ReadPictGroup);
  153.  
  154.     RTFSetReadHook ((RTFFuncPtr) NULL);
  155.  
  156.     /* dump old lists if necessary */
  157.  
  158.     while (fontList != (RTFFont *) NULL)
  159.     {
  160.         fp = fontList->rtfNextFont;
  161.         RTFFree (fontList->rtfFName);
  162.         RTFFree ((char *) fontList);
  163.         fontList = fp;
  164.     }
  165.     while (colorList != (RTFColor *) NULL)
  166.     {
  167.         cp = colorList->rtfNextColor;
  168.         RTFFree ((char *) colorList);
  169.         colorList = cp;
  170.     }
  171.     while (styleList != (RTFStyle *) NULL)
  172.     {
  173.         sp = styleList->rtfNextStyle;
  174.         eltList = styleList->rtfSSEList;
  175.         while (eltList != (RTFStyleElt *) NULL)
  176.         {
  177.             ep = eltList->rtfNextSE;
  178.             RTFFree (eltList->rtfSEText);
  179.             RTFFree ((char *) eltList);
  180.             eltList = ep;
  181.         }
  182.         RTFFree (styleList->rtfSName);
  183.         RTFFree ((char *) styleList);
  184.         styleList = sp;
  185.     }
  186.  
  187.     rtfClass = -1;
  188.     pushedClass = -1;
  189.     pushedChar = EOF;
  190. }
  191.  
  192.  
  193. /*
  194.     Set the reader's input stream to the given stream.  Can
  195.     be used to redirect to other than the default (stdin).
  196. */
  197.  
  198. void RTFSetStream (stream)
  199. FILE    *stream;
  200. {
  201.     rtffp = stream;
  202. }
  203.  
  204.  
  205. /* ---------------------------------------------------------------------- */
  206.  
  207. /*
  208.     Callback table manipulation routines
  209. */
  210.  
  211.  
  212. /*
  213.     Install or return a writer callback for a token class
  214. */
  215.  
  216.  
  217. static RTFFuncPtr    ccb[rtfMaxClass];        /* class callbacks */
  218.  
  219. void RTFSetClassCallback (class, callback)
  220. int        class;
  221. RTFFuncPtr    callback;
  222. {
  223.     if (class >= 0 && class < rtfMaxClass)
  224.         ccb[class] = callback;
  225. }
  226.  
  227.  
  228. RTFFuncPtr RTFGetClassCallback (class)
  229. int    class;
  230. {
  231.     if (class >= 0 && class < rtfMaxClass)
  232.         return (ccb[class]);
  233.     return ((RTFFuncPtr) NULL);
  234. }
  235.  
  236.  
  237. /*
  238.     Install or return a writer callback for a destination type
  239. */
  240.  
  241. static RTFFuncPtr    dcb[rtfMaxDestination];    /* destination callbacks */
  242.  
  243. void RTFSetDestinationCallback (dest, callback)
  244. int        dest;
  245. RTFFuncPtr    callback;
  246. {
  247.     if (dest >= 0 && dest < rtfMaxDestination)
  248.         dcb[dest] = callback;
  249. }
  250.  
  251.  
  252. RTFFuncPtr RTFGetDestinationCallback (dest)
  253. int    dest;
  254. {
  255.     if (dest >= 0 && dest < rtfMaxDestination)
  256.         return (dcb[dest]);
  257.     return ((RTFFuncPtr) NULL);
  258. }
  259.  
  260.  
  261. /* ---------------------------------------------------------------------- */
  262.  
  263. /*
  264.     Token reading routines
  265. */
  266.  
  267.  
  268. /*
  269.     Read the input stream, invoking the writer's callbacks
  270.     where appropriate.
  271. */
  272.  
  273. void RTFRead ()
  274. {
  275.     while (RTFGetToken () != rtfEOF)
  276.         RTFRouteToken ();
  277. }
  278.  
  279.  
  280. /*
  281.     Route a token.  If it's a destination for which a reader is
  282.     installed, process the destination internally, otherwise
  283.     pass the token to the writer's class callback.
  284. */
  285.  
  286. void RTFRouteToken ()
  287. {
  288. RTFFuncPtr    p;
  289.  
  290.     if (rtfClass < 0 || rtfClass >= rtfMaxClass)    /* watchdog */
  291.     {
  292.         Error ("Unknown class %d: %s (reader malfunction)",
  293.                             rtfClass, rtfTextBuf);
  294.     }
  295.     if (RTFCheckCM (rtfControl, rtfDestination))
  296.     {
  297.         /* invoke destination-specific callback if there is one */
  298.         if ((p = RTFGetDestinationCallback (rtfMinor))
  299.                             != (RTFFuncPtr) NULL)
  300.         {
  301.             (*p) ();
  302.             return;
  303.         }
  304.     }
  305.     /* invoke class callback if there is one */
  306.     if ((p = RTFGetClassCallback (rtfClass)) != (RTFFuncPtr) NULL)
  307.         (*p) ();
  308. }
  309.  
  310.  
  311. /*
  312.     Skip to the end of the current group.  When this returns,
  313.     writers that maintain a state stack may want to call their
  314.     state unstacker; global vars will still be set to the group's
  315.     closing brace.
  316. */
  317.  
  318. void RTFSkipGroup ()
  319. {
  320. int    level = 1;
  321.  
  322.     while (RTFGetToken () != rtfEOF)
  323.     {
  324.         if (rtfClass == rtfGroup)
  325.         {
  326.             if (rtfMajor == rtfBeginGroup)
  327.                 ++level;
  328.             else if (rtfMajor == rtfEndGroup)
  329.             {
  330.                 if (--level < 1)
  331.                     break;    /* end of initial group */
  332.             }
  333.         }
  334.     }
  335. }
  336.  
  337.  
  338. /*
  339.     Read one token.  Call the read hook if there is one.  The
  340.     token class is the return value.  Returns rtfEOF when there
  341.     are no more tokens.
  342. */
  343.  
  344. int RTFGetToken ()
  345. {
  346. RTFFuncPtr    p;
  347.  
  348.     for (;;)
  349.     {
  350.         _RTFGetToken ();
  351.         if ((p = RTFGetReadHook ()) != (RTFFuncPtr) NULL)
  352.             (*p) ();    /* give read hook a look at token */
  353.  
  354.         /* Silently discard newlines, carriage returns, nulls.  */
  355.         if (!(rtfClass == rtfText
  356.             && (rtfMajor == '\n' || rtfMajor == '\r'
  357.                         || rtfMajor == '\0')))
  358.             break;
  359.     }
  360.     return (rtfClass);
  361. }
  362.  
  363.  
  364. /*
  365.     Install or return a token reader hook.
  366. */
  367.  
  368. static RTFFuncPtr    readHook;
  369.  
  370. void RTFSetReadHook (f)
  371. RTFFuncPtr    f;
  372. {
  373.     readHook = f;
  374. }
  375.  
  376.  
  377. RTFFuncPtr RTFGetReadHook ()
  378. {
  379.     return (readHook);
  380. }
  381.  
  382.  
  383. void RTFUngetToken ()
  384. {
  385.     if (pushedClass >= 0)    /* there's already an ungotten token */
  386.         Error ("cannot unget two tokens");
  387.     if (rtfClass < 0)
  388.         Error ("no token to unget");
  389.     pushedClass = rtfClass;
  390.     pushedMajor = rtfMajor;
  391.     pushedMinor = rtfMinor;
  392.     pushedParam = rtfParam;
  393.     (void) strcpy (pushedTextBuf, rtfTextBuf);
  394. }
  395.  
  396.  
  397. int RTFPeekToken ()
  398. {
  399.     _RTFGetToken ();
  400.     RTFUngetToken ();
  401.     return (rtfClass);
  402. }
  403.  
  404.  
  405. static void _RTFGetToken ()
  406. {
  407. int    sign;
  408. int    c;
  409.  
  410.     /* check for pushed token from RTFUngetToken() */
  411.  
  412.     if (pushedClass >= 0)
  413.     {
  414.         rtfClass = pushedClass;
  415.         rtfMajor = pushedMajor;
  416.         rtfMinor = pushedMinor;
  417.         rtfParam = pushedParam;
  418.         (void) strcpy (rtfTextBuf, pushedTextBuf);
  419.         rtfTextLen = strlen (rtfTextBuf);
  420.         pushedClass = -1;
  421.         return;
  422.     }
  423.  
  424.     /* initialize token vars */
  425.  
  426.     rtfClass = rtfUnknown;
  427.     rtfParam = rtfNoParam;
  428.     rtfTextBuf[rtfTextLen = 0] = '\0';
  429.  
  430.     /* get first character, which may be a pushback from previous token */
  431.  
  432.     if (pushedChar != EOF)
  433.     {
  434.         c = pushedChar;
  435.         rtfTextBuf[rtfTextLen] = c;
  436.         rtfTextBuf[++rtfTextLen] = '\0';
  437.         pushedChar = EOF;
  438.     }
  439.     else if ((c = GetChar ()) == EOF)
  440.     {
  441.         rtfClass = rtfEOF;
  442.         return;
  443.     }
  444.  
  445.     if (c == '{')
  446.     {
  447.         rtfClass = rtfGroup;
  448.         rtfMajor = rtfBeginGroup;
  449.         return;
  450.     }
  451.     if (c == '}')
  452.     {
  453.         rtfClass = rtfGroup;
  454.         rtfMajor = rtfEndGroup;
  455.         return;
  456.     }
  457.     if (c != '\\')
  458.     {
  459.         /*
  460.             Two possibilities here:
  461.             1) ASCII 9, effectively like \tab control symbol
  462.             2) literal text char
  463.         */
  464.         if (c == '\t')            /* ASCII 9 */
  465.         {
  466.             rtfClass = rtfControl;
  467.             rtfMajor = rtfSpecialChar;
  468.             rtfMinor = rtfTab;
  469.         }
  470.         else
  471.         {
  472.             rtfClass = rtfText;
  473.             rtfMajor = c;
  474.         }
  475.         return;
  476.     }
  477.     if ((c = GetChar ()) == EOF)
  478.     {
  479.         /* early eof, whoops (class is rtfUnknown) */
  480.         return;
  481.     }
  482.     if (!isalpha (c))
  483.     {
  484.         /*
  485.             Three possibilities here:
  486.             1) hex encoded text char, e.g., \'d5, \'d3
  487.             2) special escaped text char, e.g., \{, \}
  488.             3) control symbol, e.g., \_, \-, \|, \<10>
  489.         */
  490.         if (c == '\'')                /* hex char */
  491.         {
  492.         int    c2;
  493.  
  494.             if ((c = GetChar ()) != EOF && (c2 = GetChar ()) != EOF)
  495.             {
  496.                 /* should do isxdigit check! */
  497.                 rtfClass = rtfText;
  498.                 rtfMajor = HexVal (c) * 16 + HexVal (c2);
  499.                 return;
  500.             }
  501.             /* early eof, whoops (class is rtfUnknown) */
  502.             return;
  503.         }
  504.  
  505.         if (index (":{}\\", c) != (char *) NULL) /* escaped char */
  506.         {
  507.             rtfClass = rtfText;
  508.             rtfMajor = c;
  509.             return;
  510.         }
  511.  
  512.         /* control symbol */
  513.         Lookup (rtfTextBuf);    /* sets class, major, minor */
  514.         return;
  515.     }
  516.     /* control word */
  517.     while (isalpha (c))
  518.     {
  519.         if ((c = GetChar ()) == EOF)
  520.             break;
  521.     }
  522.  
  523.     /*
  524.         At this point, the control word is all collected, so the
  525.         major/minor numbers are determined before the parameter
  526.         (if any) is scanned.  There will be one too many characters
  527.         in the buffer, though, so fix up before and restore after
  528.         looking up.
  529.     */
  530.  
  531.     if (c != EOF)
  532.         rtfTextBuf[rtfTextLen-1] = '\0';
  533.     Lookup (rtfTextBuf);    /* sets class, major, minor */
  534.     if (c != EOF)
  535.         rtfTextBuf[rtfTextLen-1] = c;
  536.  
  537.     /*
  538.         Should be looking at first digit of parameter if there
  539.         is one, unless it's negative.  In that case, next char
  540.         is '-', so need to gobble next char, and remember sign.
  541.     */
  542.  
  543.     sign = 1;
  544.     if (c == '-')
  545.     {
  546.         sign = -1;
  547.         c = GetChar ();
  548.     }
  549.     if (c != EOF && isdigit (c))
  550.     {
  551.         rtfParam = 0;
  552.         while (isdigit (c))    /* gobble parameter */
  553.         {
  554.             rtfParam = rtfParam * 10 + c - '0';
  555.             if ((c = GetChar ()) == EOF)
  556.                 break;
  557.         }
  558.         rtfParam *= sign;
  559.     }
  560.     /*
  561.         If control symbol delimiter was a blank, gobble it.
  562.         Otherwise the character is first char of next token, so
  563.         push it back for next call.  In either case, delete the
  564.         delimiter from the token buffer.
  565.     */
  566.     if (c != EOF)
  567.     {
  568.         if (c != ' ')
  569.             pushedChar = c;
  570.         rtfTextBuf[--rtfTextLen] = '\0';
  571.     }
  572.     return;
  573. }
  574.  
  575.  
  576. /*
  577.     Distributions up through 1.04 assumed high bit could be set in
  578.     RTF file characters.  Beginning with 1.05, that's not true, but
  579.     still check and ignore such characters.  (Cope with things like
  580.     WriteNow on NeXT, which generates bad RTF by writing 8-bit
  581.     characters.)
  582. */
  583.  
  584. static int GetChar ()
  585. {
  586. int    c;
  587.  
  588.     if ((c = getc (rtffp)) != EOF)
  589.     {
  590.         if (c & 0x80)
  591.         {
  592.             fprintf (stderr, "Character found with high bit set");
  593.             fprintf (stderr, " (%#x) -> changed to '?'\n", c);
  594.             c = '?';
  595.         }
  596.         rtfTextBuf[rtfTextLen] = c;
  597.         rtfTextBuf[++rtfTextLen] = '\0';
  598.     }
  599.     return (c);
  600. }
  601.  
  602.  
  603. static int HexVal (c)
  604. char    c;
  605. {
  606.     if (isupper (c))
  607.         c = tolower (c);
  608.     if (isdigit (c))
  609.         return (c - '0');    /* '0'..'9' */
  610.     return (c - 'a' + 10);        /* 'a'..'f' */
  611. }
  612.  
  613.  
  614. /*
  615.     Synthesize a token by setting the global variables to the
  616.     values supplied.  Typically this is followed with a call
  617.     to RTFRouteToken().
  618.  
  619.     If param is non-negative, it becomes part of the token text.
  620. */
  621.  
  622. void RTFSetToken (class, major, minor, param, text)
  623. int    class, major, minor, param;
  624. char    *text;
  625. {
  626.     rtfClass = class;
  627.     rtfMajor = major;
  628.     rtfMinor = minor;
  629.     rtfParam = param;
  630.     if (param == rtfNoParam)
  631.         (void) strcpy (rtfTextBuf, text);
  632.     else
  633.         sprintf (rtfTextBuf, "%s%d", text, param);
  634.     rtfTextLen = strlen (rtfTextBuf);
  635. }
  636.  
  637.  
  638. /* ---------------------------------------------------------------------- */
  639.  
  640. /*
  641.     Special destination readers.  They gobble the destination so the
  642.     writer doesn't have to deal with them.  That's wrong for any
  643.     translator that wants to process any of these itself.  In that
  644.     case, these readers should be overridden by installing a different
  645.     destination callback.
  646.  
  647.     NOTE: The last token read by each of these reader will be the
  648.     destination's terminating '}', which will then be the current token.
  649.     That '}' token is passed to RTFRouteToken() - the writer has already
  650.     seen the '{' that began the destination group, and may have pushed a
  651.     state; it also needs to know at the end of the group that a state
  652.     should be popped.
  653.  
  654.     It's important that rtf.h and the control token lookup table list
  655.     as many symbols as possible, because these readers unfortunately
  656.     make strict assumptions about the input they expect, and a token
  657.     of class rtfUnknown will throw them off easily.
  658. */
  659.  
  660.  
  661. /*
  662.     Read { \fonttbl ... } destination.  Old font tables don't have
  663.     braces around each table entry; try to adjust for that.
  664. */
  665.  
  666. static void ReadFontTbl ()
  667. {
  668. RTFFont    *fp;
  669. char    buf[rtfBufSiz], *bp;
  670. int    old = -1;
  671.  
  672.     for (;;)
  673.     {
  674.         (void) RTFGetToken ();
  675.         if (RTFCheckCM (rtfGroup, rtfEndGroup))
  676.             break;
  677.         if (old < 0)        /* first entry - determine tbl type */
  678.         {
  679.             if (RTFCheckCMM (rtfControl, rtfCharAttr, rtfFontNum))
  680.                 old = 1;    /* no brace */
  681.             else if (RTFCheckCM (rtfGroup, rtfBeginGroup))
  682.                 old = 0;    /* brace */
  683.             else            /* can't tell! */
  684.                 Error ("FTErr - Cannot determine format");
  685.         }
  686.         if (old == 0)        /* need to find "{" here */
  687.         {
  688.             if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
  689.                 Error ("FTErr - missing \"{\"");
  690.             (void) RTFGetToken ();    /* yes, skip to next token */
  691.         }
  692.         if ((fp = New (RTFFont)) == (RTFFont *) NULL)
  693.             Error ("FTErr - cannot allocate font entry");
  694.         fp->rtfNextFont = fontList;
  695.         fontList = fp;
  696.         if (!RTFCheckCMM (rtfControl, rtfCharAttr, rtfFontNum))
  697.             Error ("FTErr - missing font number");
  698.         fp->rtfFNum = rtfParam;
  699.         (void) RTFGetToken ();
  700.         if (!RTFCheckCM (rtfControl, rtfFontFamily))
  701.             Error ("FTErr - missing font family");
  702.         fp->rtfFFamily = rtfMinor;
  703.         bp = buf;
  704.         while (RTFGetToken () == rtfText)
  705.         {
  706.             if (rtfMajor == ';')
  707.                 break;
  708.             *bp++ = rtfMajor;
  709.         }
  710.         *bp = '\0';
  711.         if (buf[0] == '\0')
  712.             Error ("FTErr - missing font name");
  713.         if ((fp->rtfFName = RTFStrSave (buf)) == (char *) NULL)
  714.             Error ("FTErr - cannot allocate font name");
  715.         if (old == 0)    /* need to see "}" here */
  716.         {
  717.             (void) RTFGetToken ();
  718.             if (!RTFCheckCM (rtfGroup, rtfEndGroup))
  719.                 Error ("FTErr - missing \"}\"");
  720.         }
  721.     }
  722.     RTFRouteToken ();    /* feed "}" back to router */
  723. }
  724.  
  725.  
  726. /*
  727.     The color table entries have color values of -1 if
  728.     the default color should be used for the entry (only
  729.     a semi-colon is given in the definition, no color values).
  730.     There will be a problem if a partial entry (1 or 2 but
  731.     not 3 color values) is given.  The possibility is ignored
  732.     here.
  733. */
  734.  
  735. static void ReadColorTbl ()
  736. {
  737. RTFColor    *cp;
  738. int        cnum = 0;
  739.  
  740.     for (;;)
  741.     {
  742.         (void) RTFGetToken ();
  743.         if (RTFCheckCM (rtfGroup, rtfEndGroup))
  744.             break;
  745.         if ((cp = New (RTFColor)) == (RTFColor *) NULL)
  746.             Error ("CTErr - cannot allocate color entry");
  747.         cp->rtfCNum = cnum++;
  748.         cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
  749.         cp->rtfNextColor = colorList;
  750.         colorList = cp;
  751.         for (;;)
  752.         {
  753.             if (!RTFCheckCM (rtfControl, rtfColorName))
  754.                 break;
  755.             switch (rtfMinor)
  756.             {
  757.             case rtfRed:    cp->rtfCRed = rtfParam; break;
  758.             case rtfGreen:    cp->rtfCGreen = rtfParam; break;
  759.             case rtfBlue:    cp->rtfCBlue = rtfParam; break;
  760.             }
  761.             RTFGetToken ();
  762.         }
  763.         if (!RTFCheckCM (rtfText, (int) ';'))
  764.             Error ("CTErr - malformed entry");
  765.     }
  766.     RTFRouteToken ();    /* feed "}" back to router */
  767. }
  768.  
  769.  
  770. /*
  771.     The "Normal" style definition doesn't contain any style number
  772.     (why?), all others do.  Normal style is given style 0.
  773. */
  774.  
  775. static void ReadStyleSheet ()
  776. {
  777. RTFStyle    *sp;
  778. RTFStyleElt    *sep, *sepLast;
  779. char        buf[rtfBufSiz], *bp;
  780.  
  781.     for (;;)
  782.     {
  783.         (void) RTFGetToken ();
  784.         if (RTFCheckCM (rtfGroup, rtfEndGroup))
  785.             break;
  786.         if ((sp = New (RTFStyle)) == (RTFStyle *) NULL)
  787.             Error ("SSErr - cannot allocate stylesheet entry");
  788.         sp->rtfSNum = -1;
  789.         sp->rtfSBasedOn = rtfBasedOnNone;
  790.         sp->rtfSNextPar = -1;
  791.         sp->rtfSSEList = sepLast = (RTFStyleElt *) NULL;
  792.         sp->rtfNextStyle = styleList;
  793.         sp->rtfExpanding = 0;
  794.         styleList = sp;
  795.         if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
  796.             Error ("SSErr - missing \"{\"");
  797.         for (;;)
  798.         {
  799.             /*
  800.                 This passes over "{\*\keycode ... }".  A
  801.                 temporary (hopefully) hack.
  802.             */
  803.             if (RTFGetToken () != rtfControl)
  804.             {
  805.                 if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
  806.                     break;
  807.                 RTFSkipGroup ();
  808.                 continue;
  809.             }
  810.             if (RTFCheckMM (rtfParAttr, rtfStyleNum))
  811.             {
  812.                 sp->rtfSNum = rtfParam;
  813.                 continue;
  814.             }
  815.             if (RTFCheckMM (rtfStyleAttr, rtfBasedOn))
  816.             {
  817.                 sp->rtfSBasedOn = rtfParam;
  818.                 continue;
  819.             }
  820.             if (RTFCheckMM (rtfStyleAttr, rtfNext))
  821.             {
  822.                 sp->rtfSNextPar = rtfParam;
  823.                 continue;
  824.             }
  825.             if ((sep = New (RTFStyleElt)) == (RTFStyleElt *) NULL)
  826.                 Error ("SSErr - cannot allocate style element");
  827.             sep->rtfSEClass = rtfClass;
  828.             sep->rtfSEMajor = rtfMajor;
  829.             sep->rtfSEMinor = rtfMinor;
  830.             sep->rtfSEParam = rtfParam;
  831.             if ((sep->rtfSEText = RTFStrSave (rtfTextBuf))
  832.                             == (char *) NULL)
  833.                 Error ("SSErr - cannot allocate style element text");
  834.             if (sepLast == (RTFStyleElt *) NULL)
  835.                 sp->rtfSSEList = sep;    /* first element */
  836.             else                /* add to end */
  837.                 sepLast->rtfNextSE = sep;
  838.             sep->rtfNextSE = (RTFStyleElt *) NULL;
  839.             sepLast = sep;
  840.         }
  841.         if (sp->rtfSNextPar == -1)        /* \snext not given */
  842.             sp->rtfSNextPar = sp->rtfSNum;    /* next is itself */
  843.         if (rtfClass != rtfText)
  844.             Error ("SSErr - missing style name");
  845.         bp = buf;
  846.         while (rtfClass == rtfText)
  847.         {
  848.             if (rtfMajor == ';')
  849.             {
  850.                 (void) RTFGetToken ();
  851.                 break;
  852.             }
  853.             *bp++ = rtfMajor;
  854.             (void) RTFGetToken ();
  855.         }
  856.         *bp = '\0';
  857.         /*
  858.             If no style number was specified, check whether it's
  859.             the Normal style (in which case it's style 0).  Note
  860.             that some "normal" style names just begin with
  861.             "Normal" and can have other stuff following, e.g.,
  862.             "Normal,Times 10 point".  Ugh.
  863.  
  864.             Some German writers use "Standard" instead of "Normal".
  865.         */
  866.         if (sp->rtfSNum < 0)
  867.         {
  868.             if (strncmp (buf, "Normal", 6) != 0
  869.                 && strncmp (buf, "Standard", 8) != 0)
  870.                 Error ("SSErr - missing style number");
  871.             sp->rtfSNum = 0;
  872.         }
  873.         if ((sp->rtfSName = RTFStrSave (buf)) == (char *) NULL)
  874.             Error ("SSErr - cannot allocate style name");
  875.         if (!RTFCheckCM (rtfGroup, rtfEndGroup))
  876.             Error ("SSErr - missing \"}\"");
  877.     }
  878.     RTFRouteToken ();    /* feed "}" back to router */
  879. }
  880.  
  881.  
  882. static void ReadInfoGroup ()
  883. {
  884.     RTFSkipGroup ();
  885.     RTFRouteToken ();    /* feed "}" back to router */
  886. }
  887.  
  888.  
  889. static void ReadPictGroup ()
  890. {
  891.     RTFSkipGroup ();
  892.     RTFRouteToken ();    /* feed "}" back to router */
  893. }
  894.  
  895.  
  896. /* ---------------------------------------------------------------------- */
  897.  
  898. /*
  899.     Routines to return pieces of stylesheet, or font or color tables
  900. */
  901.  
  902.  
  903. RTFStyle *RTFGetStyle (num)
  904. int    num;
  905. {
  906. RTFStyle    *s;
  907.  
  908.     if (num == -1)
  909.         return (styleList);
  910.     for (s = styleList; s != (RTFStyle *) NULL; s = s->rtfNextStyle)
  911.     {
  912.         if (s->rtfSNum == num)
  913.             break;
  914.     }
  915.     return (s);        /* NULL if not found */
  916. }
  917.  
  918.  
  919. RTFFont *RTFGetFont (num)
  920. int    num;
  921. {
  922. RTFFont    *f;
  923.  
  924.     if (num == -1)
  925.         return (fontList);
  926.     for (f = fontList; f != (RTFFont *) NULL; f = f->rtfNextFont)
  927.     {
  928.         if (f->rtfFNum == num)
  929.             break;
  930.     }
  931.     return (f);        /* NULL if not found */
  932. }
  933.  
  934.  
  935. RTFColor *RTFGetColor (num)
  936. int    num;
  937. {
  938. RTFColor    *c;
  939.  
  940.     if (num == -1)
  941.         return (colorList);
  942.     for (c = colorList; c != (RTFColor *) NULL; c = c->rtfNextColor)
  943.     {
  944.         if (c->rtfCNum == num)
  945.             break;
  946.     }
  947.     return (c);        /* NULL if not found */
  948. }
  949.  
  950.  
  951. /* ---------------------------------------------------------------------- */
  952.  
  953.  
  954. /*
  955.     Expand style n, if there is such a style.
  956. */
  957.  
  958. void RTFExpandStyle (n)
  959. int    n;
  960. {
  961. RTFStyle    *s;
  962. RTFStyleElt    *se;
  963.  
  964.     if (n == -1 || (s = RTFGetStyle (n)) == (RTFStyle *) NULL)
  965.         return;
  966.     if (s->rtfExpanding != 0)
  967.         Error ("Style expansion loop, style %d", n);
  968.     s->rtfExpanding = 1;    /* set expansion flag for loop detection */
  969.     /*
  970.         Expand "based-on" style.  This is done by synthesizing
  971.         the token that the writer needs to see in order to trigger
  972.         another style expansion, and feeding to token back through
  973.         the router so the writer sees it.
  974.     */
  975.     RTFSetToken (rtfControl, rtfParAttr, rtfStyleNum, s->rtfSBasedOn, "\\s");
  976.     RTFRouteToken ();
  977.     /*
  978.         Now route the tokens unique to this style.  RTFSetToken()
  979.         isn't used because it would add the param value to the end
  980.         of the token text, which already has it in.
  981.     */
  982.     for (se = s->rtfSSEList; se != (RTFStyleElt *) NULL; se = se->rtfNextSE)
  983.     {
  984.         rtfClass = se->rtfSEClass;
  985.         rtfMajor = se->rtfSEMajor;
  986.         rtfMinor = se->rtfSEMinor;
  987.         rtfParam = se->rtfSEParam;
  988.         (void) strcpy (rtfTextBuf, se->rtfSEText);
  989.         rtfTextLen = strlen (rtfTextBuf);
  990.         RTFRouteToken ();
  991.     }
  992.     s->rtfExpanding = 0;    /* done - clear expansion flag */
  993. }
  994.  
  995.  
  996. /* ---------------------------------------------------------------------- */
  997.  
  998. /*
  999.     Control symbol lookup routines
  1000. */
  1001.  
  1002.  
  1003. typedef struct RTFKey    RTFKey;
  1004.  
  1005. struct RTFKey
  1006. {
  1007.     int    rtfKMajor;    /* major number */
  1008.     int    rtfKMinor;    /* minor number */
  1009.     char    *rtfKStr;    /* symbol name */
  1010.     int    rtfKHash;    /* symbol name hash value */
  1011. };
  1012.  
  1013. /*
  1014.     A minor number of -1 means the token has no minor number
  1015.     (all valid minor numbers are >= 0).
  1016. */
  1017.  
  1018. static RTFKey    rtfKey[] =
  1019. {
  1020.     rtfSpecialChar,    rtfCurHeadPict,        "chpict",    0,    /* ?? */
  1021.  
  1022.     rtfSpecialChar,    rtfCurHeadDate,        "chdate",    0,
  1023.     rtfSpecialChar,    rtfCurHeadTime,        "chtime",    0,
  1024.     rtfSpecialChar,    rtfCurHeadPage,        "chpgn",    0,
  1025.     rtfSpecialChar,    rtfCurFNote,        "chftn",    0,
  1026.     rtfSpecialChar,    rtfCurAnnotRef,        "chatn",    0,
  1027.     rtfSpecialChar,    rtfFNoteSep,        "chftnsep",    0,
  1028.     rtfSpecialChar,    rtfFNoteCont,        "chftnsepc",    0,
  1029.     rtfSpecialChar,    rtfFormula,        "|",        0,
  1030.     rtfSpecialChar,    rtfNoBrkSpace,        "~",        0,
  1031.     rtfSpecialChar,    rtfNoReqHyphen,        "-",        0,
  1032.     rtfSpecialChar,    rtfNoBrkHyphen,        "_",        0,
  1033.     rtfSpecialChar,    rtfCell,        "cell",        0,
  1034.     rtfSpecialChar,    rtfRow,            "row",        0,
  1035.     rtfSpecialChar,    rtfPar,            "par",        0,
  1036.     rtfSpecialChar,    rtfPar,            "\n",        0,
  1037.     rtfSpecialChar,    rtfPar,            "\r",        0,
  1038.     rtfSpecialChar,    rtfSect,        "sect",        0,
  1039.     rtfSpecialChar,    rtfPage,        "page",        0,
  1040.     rtfSpecialChar,    rtfColumn,        "column",    0,
  1041.     rtfSpecialChar,    rtfLine,        "line",        0,
  1042.     rtfSpecialChar,    rtfTab,            "tab",        0,
  1043.     rtfSpecialChar,    rtfOptDest,        "*",        0,
  1044.     rtfSpecialChar,    rtfIIntVersion,        "vern",        0,
  1045.     rtfSpecialChar,    rtfICreateTime,        "creatim",    0,
  1046.     rtfSpecialChar,    rtfIRevisionTime,    "revtim",    0,
  1047.     rtfSpecialChar,    rtfIPrintTime,        "printim",    0,
  1048.     rtfSpecialChar,    rtfIBackupTime,        "buptim",    0,
  1049.     rtfSpecialChar,    rtfIEditTime,        "edmins",    0,
  1050.     rtfSpecialChar,    rtfIYear,        "yr",        0,
  1051.     rtfSpecialChar,    rtfIMonth,        "mo",        0,
  1052.     rtfSpecialChar,    rtfIDay,        "dy",        0,
  1053.     rtfSpecialChar,    rtfIHour,        "hr",        0,
  1054.     rtfSpecialChar,    rtfIMinute,        "min",        0,
  1055.     rtfSpecialChar,    rtfINPages,        "nofpages",    0,
  1056.     rtfSpecialChar,    rtfINWords,        "nofwords",    0,
  1057.     rtfSpecialChar,    rtfINChars,        "nofchars",    0,
  1058.     rtfSpecialChar,    rtfIIntID,        "id",        0,
  1059.     rtfSpecialChar,    rtfBullet,        "bullet",    0,
  1060.     rtfSpecialChar,    rtfEmDash,        "emdash",    0,
  1061.     rtfSpecialChar,    rtfEnDash,        "endash",    0,
  1062.     rtfSpecialChar,    rtfLQuote,        "lquote",    0,
  1063.     rtfSpecialChar,    rtfRQuote,        "rquote",    0,
  1064.     rtfSpecialChar,    rtfLDblQuote,        "ldblquote",    0,
  1065.     rtfSpecialChar,    rtfRDblQuote,        "rdblquote",    0,
  1066.  
  1067.     rtfCharAttr,    rtfPlain,        "plain",    0,
  1068.     rtfCharAttr,    rtfBold,        "b",        0,
  1069.     rtfCharAttr,    rtfItalic,        "i",        0,
  1070.     rtfCharAttr,    rtfStrikeThru,        "strike",    0,
  1071.     rtfCharAttr,    rtfOutline,        "outl",        0,
  1072.     rtfCharAttr,    rtfShadow,        "shad",        0,
  1073.     rtfCharAttr,    rtfSmallCaps,        "scaps",    0,
  1074.     rtfCharAttr,    rtfAllCaps,        "caps",        0,
  1075.     rtfCharAttr,    rtfInvisible,        "v",        0,
  1076.     rtfCharAttr,    rtfFontNum,        "f",        0,
  1077.     rtfCharAttr,    rtfFontSize,        "fs",        0,
  1078.     rtfCharAttr,    rtfExpand,        "expnd",    0,
  1079.     rtfCharAttr,    rtfUnderline,        "ul",        0,
  1080.     rtfCharAttr,    rtfWUnderline,        "ulw",        0,
  1081.     rtfCharAttr,    rtfDUnderline,        "uld",        0,
  1082.     rtfCharAttr,    rtfDbUnderline,        "uldb",        0,
  1083.     rtfCharAttr,    rtfNoUnderline,        "ulnone",    0,
  1084.     rtfCharAttr,    rtfSuperScript,        "up",        0,
  1085.     rtfCharAttr,    rtfSubScript,        "dn",        0,
  1086.     rtfCharAttr,    rtfRevised,        "revised",    0,
  1087.     rtfCharAttr,    rtfForeColor,        "cf",        0,
  1088.     rtfCharAttr,    rtfBackColor,        "cb",        0,
  1089.     rtfCharAttr,    rtfGray,        "gray",        0,
  1090.     rtfCharAttr,    rtfLanguage,        "lang",        0,
  1091.  
  1092.     rtfParAttr,    rtfParDef,        "pard",        0,
  1093.     rtfParAttr,    rtfStyleNum,        "s",        0,
  1094.     /* next two are variants for \s that have been seen in Germany */
  1095.     rtfParAttr,    rtfStyleNum,        "cs",        0,
  1096.     rtfParAttr,    rtfStyleNum,        "ds",        0,
  1097.     rtfParAttr,    rtfQuadLeft,        "ql",        0,
  1098.     rtfParAttr,    rtfQuadRight,        "qr",        0,
  1099.     rtfParAttr,    rtfQuadJust,        "qj",        0,
  1100.     rtfParAttr,    rtfQuadCenter,        "qc",        0,
  1101.     rtfParAttr,    rtfFirstIndent,        "fi",        0,
  1102.     rtfParAttr,    rtfLeftIndent,        "li",        0,
  1103.     rtfParAttr,    rtfRightIndent,        "ri",        0,
  1104.     rtfParAttr,    rtfSpaceBefore,        "sb",        0,
  1105.     rtfParAttr,    rtfSpaceAfter,        "sa",        0,
  1106.     rtfParAttr,    rtfSpaceBetween,    "sl",        0,
  1107.     rtfParAttr,    rtfInTable,        "intbl",    0,
  1108.     rtfParAttr,    rtfKeep,        "keep",        0,
  1109.     rtfParAttr,    rtfKeepNext,        "keepn",    0,
  1110.     rtfParAttr,    rtfSideBySide,        "sbys",        0,
  1111.     rtfParAttr,    rtfPBBefore,        "pagebb",    0,
  1112.     rtfParAttr,    rtfNoLineNum,        "noline",    0,
  1113.     rtfParAttr,    rtfTabPos,        "tx",        0,
  1114.     rtfParAttr,    rtfTabRight,        "tqr",        0,
  1115.     rtfParAttr,    rtfTabCenter,        "tqc",        0,
  1116.     rtfParAttr,    rtfTabDecimal,        "tqdec",    0,
  1117.     rtfParAttr,    rtfTabBar,        "tb",        0,
  1118.     rtfParAttr,    rtfBorderTop,        "brdrt",    0,
  1119.     rtfParAttr,    rtfBorderBottom,    "brdrb",    0,
  1120.     rtfParAttr,    rtfBorderLeft,        "brdrl",    0,
  1121.     rtfParAttr,    rtfBorderRight,        "brdrr",    0,
  1122.     rtfParAttr,    rtfBorderBar,        "bar",        0,
  1123.     rtfParAttr,    rtfBorderBox,        "box",        0,
  1124.     rtfParAttr,    rtfBorderBetween,    "brdrbtw",    0,
  1125.     rtfParAttr,    rtfBorderSingle,    "brdrs",    0,
  1126.     rtfParAttr,    rtfBorderThick,        "brdrth",    0,
  1127.     rtfParAttr,    rtfBorderShadow,    "brdrsh",    0,
  1128.     rtfParAttr,    rtfBorderDouble,    "brdrdb",    0,
  1129.     rtfParAttr,    rtfBorderDot,        "brdrdot",    0,
  1130.     rtfParAttr,    rtfBorderHair,        "brdrhair",    0,
  1131.     rtfParAttr,    rtfBorderWidth,        "brdrw",    0,
  1132.     rtfParAttr,    rtfBorderColor,        "brdrcf",    0,
  1133.     rtfParAttr,    rtfBorderSpace,        "brsp",        0,
  1134.     rtfParAttr,    rtfLeaderDot,        "tldot",    0,
  1135.     rtfParAttr,    rtfLeaderHyphen,    "tlhyph",    0,
  1136.     rtfParAttr,    rtfLeaderUnder,        "tlul",        0,
  1137.     rtfParAttr,    rtfLeaderThick,        "tlth",        0,
  1138.  
  1139.     rtfSectAttr,    rtfSectDef,        "sectd",    0,
  1140.     /*rtfSectAttr,    rtfNoBreak,        "nobreak",    0,
  1141.     rtfSectAttr,    rtfColBreak,        "colbreak",    0,
  1142.     rtfSectAttr,    rtfPageBreak,        "pagebreak",    0,
  1143.     rtfSectAttr,    rtfEvenBreak,        "evenbreak",    0,
  1144.     rtfSectAttr,    rtfOddBreak,        "oddbreak",    0,*/
  1145.     rtfSectAttr,    rtfNoBreak,        "sbknone",    0,
  1146.     rtfSectAttr,    rtfColBreak,        "sbkcol",    0,
  1147.     rtfSectAttr,    rtfPageBreak,        "sbkpage",    0,
  1148.     rtfSectAttr,    rtfEvenBreak,        "sbkeven",    0,
  1149.     rtfSectAttr,    rtfOddBreak,        "sbkodd",    0,
  1150.     rtfSectAttr,    rtfPageCont,        "pgncont",    0,
  1151.     rtfSectAttr,    rtfPageStarts,        "pgnstarts",    0,
  1152.     rtfSectAttr,    rtfPageRestart,        "pgnrestart",    0,
  1153.     rtfSectAttr,    rtfPageDecimal,        "pgndec",    0,
  1154.     rtfSectAttr,    rtfPageURoman,        "pgnucrm",    0,
  1155.     rtfSectAttr,    rtfPageLRoman,        "pgnlcrm",    0,
  1156.     rtfSectAttr,    rtfPageULetter,        "pgnucltr",    0,
  1157.     rtfSectAttr,    rtfPageLLetter,        "pgnlcltr",    0,
  1158.     rtfSectAttr,    rtfPageNumLeft,        "pgnx",        0,
  1159.     rtfSectAttr,    rtfPageNumTop,        "pgny",        0,
  1160.     rtfSectAttr,    rtfHeaderY,        "headery",    0,
  1161.     rtfSectAttr,    rtfFooterY,        "footery",    0,
  1162.     rtfSectAttr,    rtfLineModulus,        "linemod",    0,
  1163.     rtfSectAttr,    rtfLineDist,        "linex",    0,
  1164.     rtfSectAttr,    rtfLineStarts,        "linestarts",    0,
  1165.     rtfSectAttr,    rtfLineRestart,        "linerestart",    0,
  1166.     rtfSectAttr,    rtfLineRestartPg,    "lineppage",    0,
  1167.     rtfSectAttr,    rtfLineCont,        "linecont",    0,
  1168.     rtfSectAttr,    rtfTopVAlign,        "vertalt",    0,
  1169.     rtfSectAttr,    rtfBottomVAlign,    "vertal",    0,
  1170.     rtfSectAttr,    rtfCenterVAlign,    "vertalc",    0,
  1171.     rtfSectAttr,    rtfJustVAlign,        "vertalj",    0,
  1172.     rtfSectAttr,    rtfColumns,        "cols",        0,
  1173.     rtfSectAttr,    rtfColumnSpace,        "colsx",    0,
  1174.     rtfSectAttr,    rtfColumnLine,        "linebetcol",    0,
  1175.     rtfSectAttr,    rtfENoteHere,        "endnhere",    0,
  1176.     rtfSectAttr,    rtfTitleSpecial,    "titlepg",    0,
  1177.     rtfSectAttr,    rtfPrtBinFirst,        "binfsxn",    0,
  1178.     rtfSectAttr,    rtfPrtBin,        "binsxn",    0,
  1179.  
  1180.     rtfDocAttr,    rtfPaperWidth,        "paperw",    0,
  1181.     rtfDocAttr,    rtfPaperHeight,        "paperh",    0,
  1182.     rtfDocAttr,    rtfLeftMargin,        "margl",    0,
  1183.     rtfDocAttr,    rtfRightMargin,        "margr",    0,
  1184.     rtfDocAttr,    rtfTopMargin,        "margt",    0,
  1185.     rtfDocAttr,    rtfBottomMargin,    "margb",    0,
  1186.     rtfDocAttr,    rtfFacingPage,        "facingp",    0,
  1187.     rtfDocAttr,    rtfGutterWid,        "gutter",    0,
  1188.     rtfDocAttr,    rtfDefTab,        "deftab",    0,
  1189.     rtfDocAttr,    rtfWidowCtrl,        "widowctrl",    0,
  1190.     rtfDocAttr,    rtfHyphHotZone,        "hyphhotz",    0,
  1191.     rtfDocAttr,    rtfFNoteEndSect,    "endnotes",    0,
  1192.     rtfDocAttr,    rtfFNoteEndDoc,        "enddoc",    0,
  1193.     rtfDocAttr,    rtfFNoteBottom,        "ftnbj",    0,
  1194.     rtfDocAttr,    rtfFNoteText,        "ftntj",    0,
  1195.     rtfDocAttr,    rtfFNoteStart,        "ftnstart",    0,
  1196.     rtfDocAttr,    rtfFNoteRestart,    "ftnrestart",    0,
  1197.     rtfDocAttr,    rtfPageStart,        "pgnstart",    0,
  1198.     rtfDocAttr,    rtfLineStart,        "linestart",    0,
  1199.     rtfDocAttr,    rtfLandscape,        "landscape",    0,
  1200.     rtfDocAttr,    rtfFracWidth,        "fracwidth",    0,
  1201.     rtfDocAttr,    rtfNextFile,        "nextfile",    0,
  1202.     rtfDocAttr,    rtfTemplate,        "template",    0,
  1203.     rtfDocAttr,    rtfMakeBackup,        "makeback",    0,
  1204.     rtfDocAttr,    rtfMakeBackup,        "makebackup",    0,
  1205.     rtfDocAttr,    rtfRTFDefault,        "defformat",    0,
  1206.     rtfDocAttr,    rtfRevisions,        "revisions",    0,
  1207.     rtfDocAttr,    rtfMirrorMargin,    "margmirror",    0,
  1208.     rtfDocAttr,    rtfRevDisplay,        "revprop",    0,
  1209.     rtfDocAttr,    rtfRevBar,        "revbar",    0,
  1210.     rtfDocAttr,    rtfDefLanguage,        "deflang",    0,
  1211.  
  1212.     rtfStyleAttr,    rtfBasedOn,        "sbasedon",    0,
  1213.     rtfStyleAttr,    rtfNext,        "snext",    0,
  1214.  
  1215.     rtfPictAttr,    rtfMacQD,        "macpict",    0,
  1216.     rtfPictAttr,    rtfWinMetafile,        "wmetafile",    0,
  1217.     rtfPictAttr,    rtfWinBitmap,        "wbitmap",    0,
  1218.     rtfPictAttr,    rtfPicWid,        "picw",        0,
  1219.     rtfPictAttr,    rtfPicHt,        "pich",        0,
  1220.     rtfPictAttr,    rtfPicGoalWid,        "picwgoal",    0,
  1221.     rtfPictAttr,    rtfPicGoalWid,        "picwGoal",    0,
  1222.     rtfPictAttr,    rtfPicGoalHt,        "pichgoal",    0,
  1223.     rtfPictAttr,    rtfPicGoalHt,        "pichGoal",    0,
  1224.     rtfPictAttr,    rtfPicScaleX,        "picscalex",    0,
  1225.     rtfPictAttr,    rtfPicScaleY,        "picscaley",    0,
  1226.     rtfPictAttr,    rtfPicScaled,        "picscaled",    0,
  1227.     rtfPictAttr,    rtfPicCropTop,        "piccropt",    0,
  1228.     rtfPictAttr,    rtfPicCropBottom,    "piccropb",    0,
  1229.     rtfPictAttr,    rtfPicCropLeft,        "piccropl",    0,
  1230.     rtfPictAttr,    rtfPicCropRight,    "piccropr",    0,
  1231.     rtfPictAttr,    rtfPixelBits,        "wbmbitspixel",    0,
  1232.     rtfPictAttr,    rtfBitmapPlanes,    "wbmplanes",    0,
  1233.     rtfPictAttr,    rtfBitmapWid,        "wbmwidthbytes", 0,
  1234.     rtfPictAttr,    rtfPicBinary,        "bin",        0,
  1235.  
  1236.     rtfNeXTGrAttr,    rtfNeXTGWidth,        "width",    0,
  1237.     rtfNeXTGrAttr,    rtfNeXTGHeight,        "height",    0,
  1238.  
  1239.     rtfDestination,    rtfPict,        "pict",        0,
  1240.     rtfDestination,    rtfNeXTGraphic,        "NeXTGraphic",    0,
  1241.     rtfDestination,    rtfFootnote,        "footnote",    0,
  1242.     rtfDestination,    rtfHeader,        "header",    0,
  1243.     rtfDestination,    rtfHeaderLeft,        "headerl",    0,
  1244.     rtfDestination,    rtfHeaderRight,        "headerr",    0,
  1245.     rtfDestination,    rtfHeaderFirst,        "headerf",    0,
  1246.     rtfDestination,    rtfFooter,        "footer",    0,
  1247.     rtfDestination,    rtfFooterLeft,        "footerl",    0,
  1248.     rtfDestination,    rtfFooterRight,        "footerr",    0,
  1249.     rtfDestination,    rtfFooterFirst,        "footerf",    0,
  1250.     rtfDestination,    rtfFNSep,        "ftnsep",    0,
  1251.     rtfDestination,    rtfFNContSep,        "ftnsepc",    0,
  1252.     rtfDestination,    rtfFNContNotice,    "ftncn",    0,
  1253.     rtfDestination,    rtfInfo,        "info",        0,
  1254.     rtfDestination,    rtfStyleSheet,        "stylesheet",    0,
  1255.     rtfDestination,    rtfFontTbl,        "fonttbl",    0,
  1256.     rtfDestination,    rtfColorTbl,        "colortbl",    0,
  1257.     rtfDestination,    rtfAnnotation,        "annotation",    0,
  1258.     rtfDestination,    rtfAnnotID,        "atnid",    0,
  1259.     rtfDestination,    rtfField,        "field",    0,
  1260.     rtfDestination,    rtfFieldInst,        "fldinst",    0,
  1261.     rtfDestination,    rtfFieldResult,        "fldrslt",    0,
  1262.     rtfDestination,    rtfIndex,        "xe",        0,
  1263.     rtfDestination,    rtfIndexBold,        "bxe",        0,
  1264.     rtfDestination,    rtfIndexItalic,        "ixe",        0,
  1265.     rtfDestination,    rtfIndexText,        "txe",        0,
  1266.     rtfDestination,    rtfIndexRange,        "rxe",        0,
  1267.     rtfDestination,    rtfTOC,            "tc",        0,
  1268.     rtfDestination,    rtfBookmarkStart,    "bkmkstart",    0,
  1269.     rtfDestination,    rtfBookmarkEnd,        "bkmkend",    0,
  1270.     rtfDestination,    rtfITitle,        "title",    0,
  1271.     rtfDestination,    rtfISubject,        "subject",    0,
  1272.     rtfDestination,    rtfIAuthor,        "author",    0,
  1273.     rtfDestination,    rtfIOperator,        "operator",    0,
  1274.     rtfDestination,    rtfIKeywords,        "keywords",    0,
  1275.     rtfDestination,    rtfIComment,        "comment",    0,
  1276.     rtfDestination,    rtfIVersion,        "version",    0,
  1277.     rtfDestination,    rtfIDoccomm,        "doccomm",    0,
  1278.     rtfDestination,    rtfIVerscomm,        "verscomm",    0,
  1279.     rtfDestination,    rtfKeyCode,        "keycode",    0,
  1280.  
  1281.     rtfTOCAttr,    rtfTOCType,        "tcf",        0,
  1282.     rtfTOCAttr,    rtfTOCLevel,        "tcl",        0,
  1283.  
  1284.     rtfFontFamily,    rtfFFNil,        "fnil",        0,
  1285.     rtfFontFamily,    rtfFFRoman,        "froman",    0,
  1286.     rtfFontFamily,    rtfFFSwiss,        "fswiss",    0,
  1287.     rtfFontFamily,    rtfFFModern,        "fmodern",    0,
  1288.     rtfFontFamily,    rtfFFScript,        "fscript",    0,
  1289.     rtfFontFamily,    rtfFFDecor,        "fdecor",    0,
  1290.     rtfFontFamily,    rtfFFTech,        "ftech",    0,
  1291.  
  1292.     rtfColorName,    rtfRed,            "red",        0,
  1293.     rtfColorName,    rtfGreen,        "green",    0,
  1294.     rtfColorName,    rtfBlue,        "blue",        0,
  1295.  
  1296.     rtfCharSet,    rtfMacCharSet,        "mac",        0,
  1297.     rtfCharSet,    rtfAnsiCharSet,        "ansi",        0,
  1298.     rtfCharSet,    rtfPcCharSet,        "pc",        0,
  1299.     rtfCharSet,    rtfPcaCharSet,        "pca",        0,
  1300.  
  1301.     rtfTblAttr,    rtfCellBordBottom,    "clbrdrb",    0,
  1302.     rtfTblAttr,    rtfCellBordTop,        "clbrdrt",    0,
  1303.     rtfTblAttr,    rtfCellBordLeft,    "clbrdrl",    0,
  1304.     rtfTblAttr,    rtfCellBordRight,    "clbrdrr",    0,
  1305.     rtfTblAttr,    rtfRowDef,        "trowd",    0,
  1306.     rtfTblAttr,    rtfRowLeft,        "trql",        0,
  1307.     rtfTblAttr,    rtfRowRight,        "trqr",        0,
  1308.     rtfTblAttr,    rtfRowCenter,        "trqc",        0,
  1309.     rtfTblAttr,    rtfRowGapH,        "trgaph",    0,
  1310.     rtfTblAttr,    rtfRowHt,        "trrh",        0,
  1311.     rtfTblAttr,    rtfRowLeftEdge,        "trleft",    0,
  1312.     rtfTblAttr,    rtfCellPos,        "cellx",    0,
  1313.     rtfTblAttr,    rtfMergeRngFirst,    "clmgf",    0,
  1314.     rtfTblAttr,    rtfMergePrevious,    "clmrg",    0,
  1315.     rtfTblAttr,    rtfCellShading,        "clshdng",    0,
  1316.  
  1317.     rtfFieldAttr,    rtfFieldDirty,        "flddirty",    0,
  1318.     rtfFieldAttr,    rtfFieldEdited,        "fldedit",    0,
  1319.     rtfFieldAttr,    rtfFieldLocked,        "fldlock",    0,
  1320.     rtfFieldAttr,    rtfFieldPrivate,    "fldpriv",    0,
  1321.  
  1322.     rtfPosAttr,    rtfPosX,        "posx",        0,
  1323.     rtfPosAttr,    rtfPosXCenter,        "posxc",    0,
  1324.     rtfPosAttr,    rtfPosXInside,        "posxi",    0,
  1325.     rtfPosAttr,    rtfPosXLeft,        "posxl",    0,
  1326.     rtfPosAttr,    rtfPosXOutSide,        "posxo",    0,
  1327.     rtfPosAttr,    rtfPosXRight,        "posxr",    0,
  1328.     rtfPosAttr,    rtfPosY,        "posy",        0,
  1329.     rtfPosAttr,    rtfPosYInline,        "posyil",    0,
  1330.     rtfPosAttr,    rtfPosYTop,        "posyt",    0,
  1331.     rtfPosAttr,    rtfPosYCenter,        "posyc",    0,
  1332.     rtfPosAttr,    rtfPosYBottom,        "posyb",    0,
  1333.     rtfPosAttr,    rtfAbsWid,        "absw",        0,
  1334.     rtfPosAttr,    rtfTextDist,        "dxfrtext",    0,
  1335.     rtfPosAttr,    rtfRPosMargV,        "pvmrg",    0,
  1336.     rtfPosAttr,    rtfRPosPageV,        "pvpg",        0,
  1337.     rtfPosAttr,    rtfRPosMargH,        "phmrg",    0,
  1338.     rtfPosAttr,    rtfRPosPageH,        "phpg",        0,
  1339.     rtfPosAttr,    rtfRPosColH,        "phcol",    0,
  1340.  
  1341.     rtfVersion,    -1,            "rtf",        0,
  1342.     rtfDefFont,    -1,            "deff",        0,
  1343.  
  1344.     0,        -1,            (char *) NULL,    0
  1345. };
  1346.  
  1347.  
  1348. /*
  1349.     Initialize lookup table hash values.  Only need to do this the
  1350.     first time it's called.
  1351. */
  1352.  
  1353. static void LookupInit ()
  1354. {
  1355. static int    inited = 0;
  1356. RTFKey    *rp;
  1357.  
  1358.     if (inited == 0)
  1359.     {
  1360.         for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++)
  1361.             rp->rtfKHash = Hash (rp->rtfKStr);
  1362.         ++inited;
  1363.     }
  1364. }
  1365.  
  1366.  
  1367. /*
  1368.     Determine major and minor number of control token.  If it's
  1369.     not found, the class turns into rtfUnknown.
  1370. */
  1371.  
  1372. static void Lookup (s)
  1373. char    *s;
  1374. {
  1375. RTFKey    *rp;
  1376. int    hash;
  1377.  
  1378.     ++s;            /* skip over the leading \ character */
  1379.     hash = Hash (s);
  1380.     for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++)
  1381.     {
  1382.         if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0)
  1383.         {
  1384.             rtfClass = rtfControl;
  1385.             rtfMajor = rp->rtfKMajor;
  1386.             rtfMinor = rp->rtfKMinor;
  1387.             return;
  1388.         }
  1389.     }
  1390.     rtfClass = rtfUnknown;
  1391. }
  1392.  
  1393.  
  1394. /*
  1395.     Compute hash value of symbol
  1396. */
  1397.  
  1398. static int Hash (s)
  1399. char    *s;
  1400. {
  1401. char    c;
  1402. int    val = 0;
  1403.  
  1404.     while ((c = *s++) != '\0')
  1405.         val += (int) c;
  1406.     return (val);
  1407. }
  1408.  
  1409.  
  1410. /*
  1411.     Print helpful error message and give up
  1412. */
  1413.  
  1414. # ifdef STDARG
  1415.  
  1416. /*
  1417.  * This version is for systems with stdarg
  1418.  */
  1419.  
  1420. static void Error (char *fmt, ...)
  1421. {
  1422.     va_list args;
  1423.     va_start (args,fmt);
  1424.     vfprintf (stderr, fmt, args);
  1425.     va_end (args);
  1426.     fprintf (stderr, "\nLast token read was \"%s\"\n", rtfTextBuf);
  1427.     exit (1);
  1428. }
  1429.  
  1430. # else /* !STDARG */
  1431. # ifdef    VARARGS
  1432.  
  1433. /*
  1434.     This version is for systems that have varargs.
  1435. */
  1436.  
  1437. static void Error (va_alist)
  1438. va_dcl
  1439. {
  1440.     va_list    args;
  1441.     char    *fmt;
  1442.  
  1443.     va_start (args);
  1444.     fmt = va_arg (args, char *);
  1445.     vfprintf (stderr, fmt, args);
  1446.     va_end (args);
  1447.     fprintf (stderr, "\nLast token read was \"%s\"\n", rtfTextBuf);
  1448.     exit (1);
  1449. }
  1450.  
  1451. # else    /* !VARARGS */
  1452.  
  1453. /*
  1454.     This version is for systems that don't have varargs.
  1455. */
  1456.  
  1457. static void Error (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  1458.     char    *fmt;
  1459.     char    *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9;
  1460. {
  1461.     fprintf (stderr, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  1462.     fprintf (stderr, "\nLast token read was \"%s\"\n", rtfTextBuf);
  1463.     exit (1);
  1464. }
  1465.  
  1466. # endif    /* !VARARGS */
  1467. # endif /* !STDARG */
  1468.  
  1469.  
  1470. /* ---------------------------------------------------------------------- */
  1471.  
  1472. /*
  1473.     Memory allocation routines
  1474. */
  1475.  
  1476.  
  1477. /*
  1478.     Return pointer to block of size bytes, or NULL if there's
  1479.     not enough memory available.
  1480. */
  1481.  
  1482. char *RTFAlloc (size)
  1483. int    size;
  1484. {
  1485.     return ((char *) malloc (size));
  1486. }
  1487.  
  1488.  
  1489. /*
  1490.     Saves a string on the heap and returns a pointer to it.
  1491. */
  1492.  
  1493.  
  1494. char *RTFStrSave (s)
  1495. char    *s;
  1496. {
  1497. char    *p;
  1498.  
  1499.     if ((p = RTFAlloc (strlen (s) + 1)) == (char *) NULL)
  1500.         return ((char *) NULL);
  1501.     return (strcpy (p, s));
  1502. }
  1503.  
  1504.  
  1505. void RTFFree (p)
  1506. char    *p;
  1507. {
  1508.     if (p != (char *) NULL)
  1509.         free (p);
  1510. }
  1511.  
  1512.  
  1513. /* ---------------------------------------------------------------------- */
  1514.  
  1515.  
  1516. /*
  1517.     Token comparison routines
  1518. */
  1519.  
  1520. int RTFCheckCM (class, major)
  1521. int    class, major;
  1522. {
  1523.     return (rtfClass == class && rtfMajor == major);
  1524. }
  1525.  
  1526.  
  1527. int RTFCheckCMM (class, major, minor)
  1528. int    class, major, minor;
  1529. {
  1530.     return (rtfClass == class && rtfMajor == major && rtfMinor == minor);
  1531. }
  1532.  
  1533.  
  1534. int RTFCheckMM (major, minor)
  1535. int    major, minor;
  1536. {
  1537.     return (rtfMajor == major && rtfMinor == minor);
  1538. }
  1539.